package com.wandian.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.text.DecimalFormat;
import java.text.MessageFormat;

/**
 * @date 2011-09-11, 12:21:18
 * @author long@7road.com
 * @description StringUtil类：字符串操作工具类，如trim，截取
 *
 */
public class StringUtil {

    private static MessageDigest digest = null;
    private static final String[] padding = {"", " ", "  ", "   ", "    ", "     ", "      ", "       ", "        ", "         ", "          "};

    /**
     * 对字符串进行MD5加密
     *
     * @param data
     * @return
     */
    public String hash(String data) {
        if (digest == null) {
            try {
                digest = MessageDigest.getInstance("MD5");
            } catch (NoSuchAlgorithmException nsae) {
                System.err.println("Failed to load the MD5 MessageDigest. We will be unable to function normally.");
                nsae.printStackTrace();
            }
        }
        digest.update(data.getBytes());
        return encodeHex(digest.digest());
    }

    private String encodeHex(byte bytes[]) {
        StringBuilder buf = new StringBuilder(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++) {
            if ((bytes[i] & 0xff) < 16) {
                buf.append("0");
            }
            buf.append(Long.toString(bytes[i] & 0xff, 16));
        }
        return buf.toString().toUpperCase();
    }

    /**
     * 在list中查询以prefix开头的子项，返回符合匹配的list
     *
     * @param list
     * @param prefix
     * @return
     */
    public List getMatches(List list, String prefix) {
        String prefix_upper = prefix.toUpperCase();
        List matches = new ArrayList();
        Iterator iter = list.iterator();
        while (iter.hasNext()) {
            String name = (String) iter.next();
            String name_upper = name.toUpperCase();
            if (name_upper.startsWith(prefix_upper)) {
                matches.add(name);
            }
        }
        return matches;
    }

    /**
     * 统计字符出现次数
     *
     * @param s
     */
    public Map<Character, Integer> getStatistics(String s) {
        Map<Character, Integer> map = new HashMap<Character, Integer>();
        int i, size = s.length();
        for (i = 0; i < size; i++) {
            char c = s.charAt(i);
            map.put(c, map.containsKey(c) ? ((Integer) map.get(c) + 1) : 1);
        }
        return map;
    }

    /**
     * 将一字符串数组用指定的分隔符接起来
     *
     * @param array
     * @param split
     * @return
     */
    public String addSplit(String[] array, String split) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < array.length - 1; i++) {
            sb.append(array[i] + split);
        }
        sb.append(array[array.length - 1]);
        return sb.toString();
    }

    /**
     * Encode string to hex string, hex string can use in url
     *
     * @param str
     * @return hex string
     */
    public static String HexEncode(String str) {
        String hexString = null;
        if (str != null && str.length() > 0) {
            char[] digital = "0123456789ABCDEF".toCharArray();
            StringBuilder sb = new StringBuilder("");
            try {
                byte[] bs = str.getBytes("utf-8");
                int bit;
                for (int i = 0; i < bs.length; i++) {
                    bit = (bs[i] & 0x0f0) >> 4;
                    sb.append(digital[bit]);
                    bit = bs[i] & 0x0f;
                    sb.append(digital[bit]);
                }
            } catch (Exception e) {
            }
            hexString = sb.toString();
        }

        return hexString;
    }

    /**
     * Decode hex string
     *
     * @param hexString
     * @return
     */
    public static String HexDecode(String hexString) {
        String str = null;
        if (hexString != null && hexString.length() > 0) {
            String digital = "0123456789ABCDEF";
            char[] hex2char = hexString.toCharArray();
            byte[] bytes = new byte[hexString.length() / 2];
            int temp;
            for (int i = 0; i < bytes.length; i++) {
                temp = digital.indexOf(hex2char[2 * i]) * 16;
                temp += digital.indexOf(hex2char[2 * i + 1]);
                bytes[i] = (byte) (temp & 0xff);
            }
            try {
                str = new String(bytes, "utf-8");
            } catch (Exception e) {
            }
        }
        return str;
    }

    /**
     * judge a string is null or empty
     *
     * @param str
     * @return return true if str is null or empty, otherwise false
     */
    public static boolean isEmpty(String str) {
        return (str == null || str.length() == 0);
    }

    /**
     * 将多余的文字用...代替（length为双字节，比如length=18，表示9个汉字）
     */
    public static String getLimitLengthString(String str, int length) {
        String view = null;
        int counterOfDoubleByte = 0;
        byte b[];
        if (str == null) {
            return "";
        } else {
            try {
                b = str.getBytes("GBK");
                if (b.length <= length) {
                    return str;
                }
                for (int i = 0; i < length; i++) {
                    if (b[i] > 0) {
                        counterOfDoubleByte++;
                    }
                }
                if (counterOfDoubleByte % 2 == 0) {
                    view = new String(b, 0, length, "GBK") + "...";
                } else {
                    view = new String(b, 0, length - 1, "GBK") + "...";
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return view;
        }
    }
//身份证效验规则  

    public boolean isIdCard(String arrIdCard) {
        int sigma = 0;
        Integer[] a = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
        String[] w = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
        for (int i = 0; i < 17; i++) {
            int ai = Integer.parseInt(arrIdCard.substring(i, i + 1));
            int wi = a[i];
            sigma += ai * wi;
        }
        int number = sigma % 11;
        String check_number = w[number];
        //return check_number;  
        //System.out.println(check_number);  
        if (!arrIdCard.substring(17).equals(check_number)) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * *
     *
     * Join a collection of strings by a seperator
     *
     * @param strings collection of string objects
     *
     * @param sep string to place between strings
     *
     * @return joined string
     *
     */
    public static String join(Collection<String> strings, String sep) {

        return join(strings.iterator(), sep);

    }

    /**
     * *
     *
     * Join a collection of strings by a seperator
     *
     * @param strings iterator of string objects
     *
     * @param sep string to place between strings
     *
     * @return joined string
     *
     */
    public static String join(Iterator<String> strings, String sep) {

        if (!strings.hasNext()) {
            return "";
        }



        String start = strings.next();

        if (!strings.hasNext()) // only one, avoid builder
        {
            return start;
        }



        StringBuilder sb = new StringBuilder(64).append(start);

        while (strings.hasNext()) {

            sb.append(sep);

            sb.append(strings.next());

        }

        return sb.toString();

    }

    /**
     * *
     *
     * Returns space padding
     *
     * @param width amount of padding desired
     *
     * @return string of spaces * width
     *
     */
    public static String padding(int width) {

        if (width < 0) {
            throw new IllegalArgumentException("width must be > 0");
        }



        if (width < padding.length) {
            return padding[width];
        }



        char[] out = new char[width];

        for (int i = 0; i < width; i++) {
            out[i] = ' ';
        }

        return String.valueOf(out);

    }

    /**
     * *
     *
     * Tests if a string is blank: null, emtpy, or only whitespace (" ", \r\n,
     * \t, etc)
     *
     * @param string string to test
     *
     * @return if string is blank
     *
     */
    public static boolean isBlank(String string) {

        if (string == null || string.length() == 0) {
            return true;
        }



        int l = string.length();

        for (int i = 0; i < l; i++) {

            if (!Character.isWhitespace(string.codePointAt(i))) {
                return false;
            }

        }

        return true;

    }

    /**
     * *
     *
     * Tests if a string is numeric, i.e. contains only digit characters
     *
     * @param string string to test
     *
     * @return true if only digit chars, false if empty or null or contains
     * non-digit chrs
     *
     */
    public static boolean isNumeric(String string) {

        if (string == null || string.length() == 0) {
            return false;
        }



        int l = string.length();

        for (int i = 0; i < l; i++) {

            if (!Character.isDigit(string.codePointAt(i))) {
                return false;
            }

        }

        return true;

    }

    public static String normaliseWhitespace(String string) {

        StringBuilder sb = new StringBuilder(string.length());



        boolean lastWasWhite = false;

        boolean modified = false;



        int l = string.length();

        for (int i = 0; i < l; i++) {

            int c = string.codePointAt(i);

            if (Character.isWhitespace(c)) {

                if (lastWasWhite) {

                    modified = true;

                    continue;

                }

                if (c != ' ') {
                    modified = true;
                }

                sb.append(' ');

                lastWasWhite = true;

            } else {

                sb.appendCodePoint(c);

                lastWasWhite = false;

            }

        }

        return modified ? sb.toString() : string;

    }

    /**
     * 文字列の部分取得。</br> {@link java.lang.String#substring(int)}
     *
     * @param strArg
     * @param beginIndex
     * @return
     */
    public static String subString(String strArg, int beginIndex) {
        if (strArg == null) {
            return "";
        }

        return subString(strArg, beginIndex, strArg.length());
    }

    public static String subString(String strArg, int beginIndex, int endIndex) {
        if (strArg == null) {
            return "";
        }

        if (strArg.length() <= beginIndex) {
            return "";
        }

        if (strArg.length() < endIndex) {
            return strArg.substring(beginIndex);
        } else {
            return strArg.substring(beginIndex, endIndex);
        }
    }

    public static String subString(String strArg, int length, String tail) {
        if (strArg == null) {
            return "";
        }

        if (strArg.length() <= length) {
            return strArg;
        }

        return strArg.substring(0, length) + tail;

    }

//    public static String subString(String strArg, int length, String tail) {
//        if (strArg == null) {
//            return "";
//        }
//
//        if (strArg.length() <= length) {
//            return strArg;
//        }
//
//        return strArg.substring(0, length) + tail;
//
//    }
    public static String Trim(String strArg, char atChar) {
        return Trim(strArg, new char[]{atChar});
    }

    public static String Trim(String strArg, char[] chars) {

        if (chars == null) {
            return strArg;
        }
        if (strArg.isEmpty()) {
            return strArg;
        }

        try {
            boolean trim = false;
            for (char c : chars) {
                if (strArg.charAt(0) == c) {
                    strArg = subString(strArg, 1);
                    trim = true;
                }
                if (strArg.charAt(strArg.length() - 1) == c) {
                    strArg = subString(strArg, 0, strArg.length() - 1);
                    trim = true;
                }
                if (trim) {
                    break;
                }
            }
        } catch (Exception ex) {
            return "";
        }
        return strArg;
    }

    public static String Trim(String strArg, String intercept) {
        return Trim(strArg, new String[]{intercept});
    }

    public static String Trim(String strArg, String[] intercepts) {

        if (intercepts == null) {
            return strArg;
        }
        if (strArg.isEmpty()) {
            return strArg;
        }

        try {
            boolean trim = false;
            for (String s : intercepts) {
                if (strArg.indexOf(s) == 0) {
                    strArg = subString(strArg, s.length());
                    trim = true;
                }
                if (strArg.lastIndexOf(s) != -1 && (strArg.lastIndexOf(s) + s.length()) == strArg.length()) {
                    strArg = subString(strArg, 0, strArg.lastIndexOf(s));
                    trim = true;
                }
                if (trim) {
                    break;
                }

            }
        } catch (Exception ex) {
            return "";
        }
        return strArg;
    }

    public static int parseInt(String strArg) {

        if (strArg == null) {
            return 0;
        }

        try {
            return Integer.parseInt(strArg);
        } catch (NumberFormatException ex) {
            return 0;
        }
    }

    public static double parseDouble(String strArg) {

        if (strArg == null) {
            return 0;
        }

        try {
            return Double.parseDouble(strArg);
        } catch (NumberFormatException ex) {
            return 0;
        }
    }

    public static String toString(Object obj) {
        return toString(obj, "");
    }

    public static String floatToString(float obj) {

        DecimalFormat format = new DecimalFormat("##");
        return format.format(obj);
    }

    public static String toString(Object obj, Object defaultvalue) {
        if (obj == null) {
            if (defaultvalue == null) {
                return "";
            } else {
                return defaultvalue.toString();
            }
        } else {
            return obj.toString();
        }
    }

    /**
     * 获取一个类的class文件所在的绝对路径。 这个类可以是JDK自身的类，也可以是用户自定义的类，或者是第三方开发包里的类。
     * 只要是在本程序中可以被加载的类，都可以定位到它的class文件的绝对路径。
     *
     * @param cls 一个对象的Class属性
     * @return 这个类的class文件位置的绝对路径。 如果没有这个类的定义，则返回null。
     */
    public static String getPathFromClass(Class cls) throws IOException {
        String path = null;
        if (cls == null) {
            throw new NullPointerException();
        }
        URL url = getClassLocationURL(cls);
        if (url != null) {
            path = url.getPath();
            if ("jar".equalsIgnoreCase(url.getProtocol())) {
                try {
                    path = new URL(path).getPath();
                } catch (MalformedURLException e) {
                }
                int location = path.indexOf("!/");
                if (location != -1) {
                    path = path.substring(0, location);
                }
            }
            File file = new File(path);
            path = file.getCanonicalPath();
        }
        return path;
    }

    /**
     * 这个方法可以通过与某个类的class文件的相对路径来获取文件或目录的绝对路径。 通常在程序中很难定位某个相对路径，特别是在B/S应用中。
     * 通过这个方法，我们可以根据我们程序自身的类文件的位置来定位某个相对路径。
     * 比如：某个txt文件相对于程序的Test类文件的路径是../../resource/test.txt，
     * 那么使用本方法Path.getFullPathRelateClass("../../resource/test.txt",Test.class)
     * 得到的结果是txt文件的在系统中的绝对路径。
     *
     * @param relatedPath 相对路径
     * @param cls 用来定位的类
     * @return 相对路径所对应的绝对路径
     * @throws IOException 因为本方法将查询文件系统，所以可能抛出IO异常
     */
    public static String getFullPathRelateClass(String relatedPath, Class cls)
            throws IOException {
        String path = null;
        if (relatedPath == null) {
            throw new NullPointerException();
        }
        String clsPath = getPathFromClass(cls);
        File clsFile = new File(clsPath);
        String tempPath = clsFile.getParent() + File.separator + relatedPath;
        File file = new File(tempPath);
        path = file.getCanonicalPath();
        return path;
    }

    /**
     * 获取类的class文件位置的URL。这个方法是本类最基础的方法，供其它方法调用。
     */
    private static URL getClassLocationURL(final Class cls) {
        if (cls == null) {
            throw new IllegalArgumentException("null input: cls");
        }
        URL result = null;
        final String clsAsResource = cls.getName().replace('.', '/').concat(
                ".class");
        final ProtectionDomain pd = cls.getProtectionDomain();
        // java.lang.Class contract does not specify
        // if 'pd' can ever be null;
        // it is not the case for Sun's implementations,
        // but guard against null
        // just in case:
        if (pd != null) {
            final CodeSource cs = pd.getCodeSource();
            // 'cs' can be null depending on
            // the classloader behavior:
            if (cs != null) {
                result = cs.getLocation();
            }

            if (result != null) {
                // Convert a code source location into
                // a full class file location
                // for some common cases:
                if ("file".equals(result.getProtocol())) {
                    try {
                        if (result.toExternalForm().endsWith(".jar")
                                || result.toExternalForm().endsWith(".zip")) {
                            result = new URL("jar:".concat(
                                    result.toExternalForm()).concat("!/").concat(clsAsResource));
                        } else if (new File(result.getFile()).isDirectory()) {
                            result = new URL(result, clsAsResource);
                        }
                    } catch (MalformedURLException ignore) {
                    }
                }
            }
        }

        if (result == null) {
            // Try to find 'cls' definition as a resource;
            // this is not
            // document．d to be legal, but Sun's
            // implementations seem to //allow this:
            final ClassLoader clsLoader = cls.getClassLoader();
            result = clsLoader != null ? clsLoader.getResource(clsAsResource)
                    : ClassLoader.getSystemResource(clsAsResource);
        }
        return result;
    }

    public static String format(String pattern, Object... arguments) {
        return MessageFormat.format(pattern, arguments);
    }

    void main(String[] args) {
        try {
            System.out.println(getPathFromClass(PathUtil.class));
            System.out.println(getFullPathRelateClass("../test/abc/..",
                    PathUtil.class));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * 字符串转换成十六进制值
     *
     * @param bin String 我们看到的要转换成十六进制的字符串
     *
     * @return
     *
     */
    public static String bin2hex(String bin) {

        char[] digital = "0123456789ABCDEF".toCharArray();

        StringBuffer sb = new StringBuffer("");

        byte[] bs = bin.getBytes();

        int bit;

        for (int i = 0; i < bs.length; i++) {

            bit = (bs[i] & 0x0f0) >> 4;

            sb.append(digital[bit]);

            bit = bs[i] & 0x0f;

            sb.append(digital[bit]);

        }

        return sb.toString();

    }

    /**
     *
     * 十六进制转换字符串
     *
     * @param hex String 十六进制
     *
     * @return String 转换后的字符串
     *
     */
    public static String hex2bin(String hex) {
        String digital = "0123456789ABCDEF";
        char[] hex2char = hex.toCharArray();
        byte[] bytes = new byte[hex.length() / 2];
        int temp;
        for (int i = 0; i < bytes.length; i++) {

            temp = digital.indexOf(hex2char[2 * i]) * 16;

            temp += digital.indexOf(hex2char[2 * i + 1]);

            bytes[i] = (byte) (temp & 0xff);

        }
        return new String(bytes);
    }

    /**
     * java字节码转字符串
     *
     * @param b
     * @return
     */
    public static String byte2hex(byte[] b) { //一个字节的数， 
        // 转成16进制字符串
        String hs = "";
        String tmp = "";
        for (int n = 0; n < b.length; n++) {
            //整数转成十六进制表示
            tmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
            if (tmp.length() == 1) {
                hs = hs + "0" + tmp;
            } else {
                hs = hs + tmp;
            }
        }

        tmp = null;
        return hs.toUpperCase(); //转成大写

    }

    /**
     * java字节码转字符串
     *
     * @param b
     * @return
     */
    public static String byte2hex(byte[] b, int length) { //一个字节的数， 
        // 转成16进制字符串
        String hs = "";
        String tmp = "";
        if (length > b.length) {
            length = b.length;
        }
        for (int n = 0; n < length; n++) {
            //整数转成十六进制表示
            tmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
            if (tmp.length() == 1) {
                hs = hs + "0" + tmp+",";
            } else {
                hs = hs + tmp+",";
            }
        }

        tmp = null;
        return hs.toUpperCase(); //转成大写

    }

    /**
     * 字符串转java字节码
     *
     * @param b
     * @return
     */
    public static byte[] hex2byte(byte[] b) {

        if ((b.length % 2) != 0) {

            throw new IllegalArgumentException("长度不是偶数");
        }

        byte[] b2 = new byte[b.length / 2];

        for (int n = 0; n < b.length; n += 2) {

            String item = new String(b, n, 2);

            // 两位一组，表示一个字节,把这样表示的16进制字符串，还原成一个进制字节
            b2[n / 2] = (byte) Integer.parseInt(item, 16);
        }

        b = null;

        return b2;

    }
}
